package online.lona.mc;

import java.io.*;
import java.lang.reflect.Field;

public abstract class LibraryUtil {

    private static boolean isToFile(final InputStream is, final File file) {
        try (FileOutputStream fos = new FileOutputStream(file, false)
        ) {
            if (fos != null) {
                BufferedInputStream bis = new BufferedInputStream(is);
                byte[] buffer = new byte[bis.available()];
                int readSize = bis.read(buffer);
                fos.write(buffer, 0, readSize);
                bis.close();
                fos.close();
                return true;
            }
        } catch (IOException e) {
            return false;
        }
        return false;
    }

    public static boolean releaseLibrary(final String libraryPath) {
        if (EnvUtil.isWindows()) {
            InputStream lib32is = LibraryUtil.class.getResourceAsStream("/windows/libymer32.dll");
            InputStream lib64is = LibraryUtil.class.getResourceAsStream("/windows/libymer64.dll");
            final File lib32File = new File(libraryPath + "/libymer32.dll");
            final File lib64File = new File(libraryPath + "/libymer64.dll");
            if (lib32is != null && lib64is != null) {
                isToFile(lib32is, lib32File);
                isToFile(lib64is, lib64File);
            }
            if (lib32is != null) {
                try {
                    lib32is.close();
                } catch (IOException e) {
                    return false;
                }
            }
            if (lib64is != null) {
                try {
                    lib64is.close();
                } catch (IOException e) {
                    return false;
                }
            }
            return true;
        } else if (EnvUtil.isLinux()) {
            final InputStream libiconv_is = LibraryUtil.class.getResourceAsStream("/linux/libiconv.so");
            final InputStream libmbedcrypto_is = LibraryUtil.class.getResourceAsStream("/linux/libmbedcrypto.so");
            final InputStream libmbedx509_is = LibraryUtil.class.getResourceAsStream("/linux/libmbedx509.so");
            final InputStream libmbedtls_is = LibraryUtil.class.getResourceAsStream("/linux/libmbedtls.so");
            final InputStream libz_is = LibraryUtil.class.getResourceAsStream("/linux/libz.so");
            final InputStream libymer_is = LibraryUtil.class.getResourceAsStream("/linux/libymer.so");
            final File libiconv_file = new File(libraryPath + "/libiconv.so");
            final File libmbedcrypto_file = new File(libraryPath + "/libmbedcrypto.so");
            final File libmbedx509_file = new File(libraryPath + "/libmbedx509.so");
            final File libmbedtls_file = new File(libraryPath + "/libmbedtls.so");
            final File libz_file = new File(libraryPath + "/libz.so");
            final File libymer_file = new File(libraryPath + "/libymer.so");

            if (libiconv_is != null && libmbedcrypto_is != null && libmbedtls_is != null && libmbedx509_is != null && libymer_is != null && libz_is != null) {
                isToFile(libiconv_is, libiconv_file);
                isToFile(libmbedcrypto_is, libmbedcrypto_file);
                isToFile(libmbedx509_is, libmbedx509_file);
                isToFile(libmbedtls_is, libmbedtls_file);
                isToFile(libz_is, libz_file);
                isToFile(libymer_is, libymer_file);
            }
            try {
                if (libiconv_is != null) {
                    libiconv_is.close();
                }
                if (libmbedcrypto_is != null) {
                    libmbedcrypto_is.close();
                }
                if (libmbedtls_is != null) {
                    libmbedtls_is.close();
                }
                if (libmbedx509_is != null) {
                    libmbedx509_is.close();
                }
                if (libz_is != null) {
                    libz_is.close();
                }
                if (libymer_is != null) {
                    libymer_is.close();
                }

            } catch (IOException e) {
                return false;
            }

            return true;
        }

        return false;
    }

    public static void addLibraryDir(String libraryPath) throws Exception {
        Field userPathsField = ClassLoader.class.getDeclaredField("usr_paths");
        userPathsField.setAccessible(true);
        String[] paths = (String[]) userPathsField.get(null);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < paths.length; i++) {
            if (libraryPath.equals(paths[i])) {
                continue;
            }
            sb.append(paths[i]).append(';');
        }
        sb.append(libraryPath);
        System.setProperty("java.library.path", sb.toString());
        final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
        sysPathsField.setAccessible(true);
        sysPathsField.set(null, null);
    }
}
